package routes

import (
	"encoding/json"
	"log"

	websocketController "gitee.com/sweetsunnyflower/carpooling-server-go/app/http/controllers/websocket"
	"gitee.com/sweetsunnyflower/carpooling-server-go/app/http/middlewares"
	"gitee.com/sweetsunnyflower/carpooling-server-go/pkg/logger"
	"github.com/gofiber/contrib/websocket"
	"github.com/gofiber/fiber/v2"
	"github.com/spf13/cast"
)

func RegisterWebsocketRoutes(app *fiber.App) {

	controller := new(websocketController.Controller)

	actions := map[string]func(c *websocket.Conn, payload map[string]interface{}) bool{
		"test":    controller.Test,
		"ping":    controller.Ping,
		"connect": controller.ClientConnect,
	}

	app.Use("/ws", func(c *fiber.Ctx) error {
		// IsWebSocketUpgrade returns true if the client
		// requested upgrade to the WebSocket protocol.
		if websocket.IsWebSocketUpgrade(c) {
			c.Locals("allowed", true)
			return c.Next()
		}
		return fiber.ErrUpgradeRequired
	})

	app.Use(middlewares.WebsocketAuth()).Get("/ws", websocket.New(func(c *websocket.Conn) {

		controller.SetUserId(c).Connect(c)

		// c.Locals is added to the *websocket.Conn
		log.Println(c.Locals("allowed"))  // true
		log.Println(c.Query("v"))         // 1.0
		log.Println(c.Cookies("session")) // ""

		// websocket.Conn bindings https://pkg.go.dev/github.com/fasthttp/websocket?tab=doc#pkg-index
		var (
			message_type int
			message      []byte
			err          error
		)
		defer func() {
			controller.Disconnect(c)
			logger.InfoString("websocket", "disconnect", cast.ToString(controller.UserId))
			c.Close()
		}()
		for {

			if message_type, message, err = c.ReadMessage(); err != nil {
				// 从连接中剔除
				logger.WarnString("websocket", "message read error", err.Error())
				break
			}
			// 解析message格式，映射到响应的controller action
			logger.InfoString("websocket message", "recv type", cast.ToString(message_type))
			logger.InfoString("websocket message", "recv message", string(message))

			if message_type == websocket.TextMessage {
				data := websocketController.Data{}
				json.Unmarshal(message, &data)
				if action, ok := actions[data.Action]; ok {
					go action(c, data.Payload)
				} else {
					controller.Error(c, fiber.Map{})
					logger.WarnString("websocket", "message type", "无效的路由 action")
					c.Close()
				}
			}
		}
	}))
}
